import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;


public class Set {
	
	/*
	 * Class representing sets of codes 
	 */

	// Attributes
	
	public ArrayList<Code> set  = new ArrayList<Code>();
	public ArrayList<Code> set1 = new ArrayList<Code>();
	public ArrayList<Code> set2 = new ArrayList<Code>();
	public ArrayList<Code> set3 = new ArrayList<Code>();
	public ArrayList<Code> set4 = new ArrayList<Code>();
	public ArrayList<Code> set5 = new ArrayList<Code>();
	public ArrayList<Code> set6 = new ArrayList<Code>();
	
	public ArrayList<Code> set1A = new ArrayList<Code>();
	public ArrayList<Code> set2A = new ArrayList<Code>();
	public ArrayList<Code> set3A = new ArrayList<Code>();
	public ArrayList<Code> set4A = new ArrayList<Code>();
	public ArrayList<Code> set5A = new ArrayList<Code>();
	public ArrayList<Code> set6A = new ArrayList<Code>();
	
	public ArrayList<Code> set1M = new ArrayList<Code>();
	public ArrayList<Code> set2M = new ArrayList<Code>();
	public ArrayList<Code> set3M = new ArrayList<Code>();
	public ArrayList<Code> set4M = new ArrayList<Code>();
	public ArrayList<Code> set5M = new ArrayList<Code>();
	public ArrayList<Code> set6M = new ArrayList<Code>();
	
	public ArrayList<Code> set1AM = new ArrayList<Code>();
	public ArrayList<Code> set2AM = new ArrayList<Code>();
	public ArrayList<Code> set3AM = new ArrayList<Code>();
	public ArrayList<Code> set4AM = new ArrayList<Code>();
	public ArrayList<Code> set5AM = new ArrayList<Code>();
	public ArrayList<Code> set6AM = new ArrayList<Code>();
	
	
	// Constructors
	
	public Set () {}
	
	public Set(Code c)
	{
		set.add(c);
	}
	
	public Set(ArrayList<Code> list)
	{
		for(Code c : list)
		{
			set.add(c);
		}
	}
	
	// Getters / setters
	
	public void add(Code c)
	{
		if (!set.contains(c))
		{
			set.add(c);
		}
	}
	
	public void add_all(Code c)
	{
		set.add(c);
	}
	
	// convert a set into a string
	public String toString ()
	{
		String str = "";
		for (Code c : set)
		{
			str += "[" + c.toString() + "]\n";
		}
		return str;
	}
	
	
	// Generation of circular codes
	
	public void construct_1(String alphabet)
	{
		int i,j;
			
		for(i=0;i<alphabet.length();i++)
		{
			for(j=0;j<alphabet.length();j++)
			{		
				Code c = new Code();
				Dinucleotide d = new Dinucleotide (alphabet.charAt(i),alphabet.charAt(j));

				// Test if circular
				if ((d.left!=d.right) && !((c.get_code()).contains(d.complementarity())))
				{
					c.add(d);
					set1.add(c);
					
					// Test d'auto-complémentarité
					if (c.equals(c.complementarity()))
					{
						set1A.add(c);
					}
				}
			}
		}	
	}
	
	public void construct_X(String alphabet, int x, ArrayList<Code> setY, ArrayList<Code> setX, ArrayList<Code> setXA, ArrayList<Code> setXM, ArrayList<Code> setXAM)
	{
		switch(x)
		{
		case 1 : construct_1(alphabet);
			break;
		case 2 : construct_X(alphabet, 1, set1, set1, set1A, set1M, set1AM);
			break;
		case 3 : construct_X(alphabet, 2, set1, set2, set2A, set2M, set2AM);
			break;
		case 4 : construct_X(alphabet, 3, set2, set3, set3A, set3M, set3AM);
			break;
		case 5 : construct_X(alphabet, 4, set3, set4, set4A, set4M, set4AM);
			break;
		case 6 : construct_X(alphabet, 5, set4, set5, set5A, set5M, set5AM);
			break;
		default : 
			break;
		}
		
		for (Code a : set1)
		{
			for (Code b : setY)
			{				
				Code tmp = new Code();
				
				Dinucleotide da = a.get_code().get(0);
				tmp.add(a);
				
			 	// test if circular
				if(!(b.get_code()).contains(da) && !(b.get_code()).contains(da.permutation()))
				{
					tmp.add(b);
					
					if (!setX.contains(tmp) && !((tmp.hasNecklace5())))
					{
						boolean c = false;
						setX.add(tmp);
						
						// Code circulaire auto-complémentaires
						if (tmp.equals(tmp.complementarity()))
						{
							c = true;
							setXA.add(tmp);
						}
						
						if (x == 1)
						{
							System.out.println("Code circulaire : " + b + " (comp:"+ c + ")");
						}
						
						// Code circulaire maximal
						if (tmp.is_maximal(set1))
						{
							if (c)
							{
								// Code circulaire auto-compl�mentaire maximal
								setXAM.add(tmp);
							}
							setXM.add(tmp);
						}
					}
				}
			}
		}
	}
	
	public void generate()
	{
		// TODO : Vérifier le contenu des fichiers, je n'ai pas le sujet
		
		try 
		{
			FileWriter f = new FileWriter("NbCC.txt");
			f.write(set1.size() + " ");
			f.write(set2.size() + " ");
			f.write(set3.size() + " ");
			f.write(set4.size() + " ");
			f.write(set5.size() + " ");
			f.write(set6.size() + "\n");
			f.close();
			
			f = new FileWriter("ListCCLg1.txt");
			f.write(display(set1));
			f.close();
			f = new FileWriter("ListCCLg2.txt");
			f.write(display(set2));
			f.close();
			f = new FileWriter("ListCCLg3.txt");
			f.write(display(set3));
			f.close();
			f = new FileWriter("ListCCLg4.txt");
			f.write(display(set4));
			f.close();
			f = new FileWriter("ListCCLg5.txt");
			f.write(display(set5));
			f.close();
			f = new FileWriter("ListCCLg6.txt");
			f.write(display(set6));
			f.close();
			
			f = new FileWriter("NbCCS.txt");
			f.write(set1A.size() + " ");
			f.write(set2A.size() + " ");
			f.write(set3A.size() + " ");
			f.write(set4A.size() + " ");
			f.write(set5A.size() + " ");
			f.write(set6A.size() + "\n");
			f.close();
			
			f = new FileWriter("ListCCSLg1.txt");
			f.write(display(set1A));
			f.close();
			f = new FileWriter("ListCCSLg2.txt");
			f.write(display(set2A));
			f.close();
			f = new FileWriter("ListCCSLg3.txt");
			f.write(display(set3A));
			f.close();
			f = new FileWriter("ListCCSLg4.txt");
			f.write(display(set4A));
			f.close();
			f = new FileWriter("ListCCSLg5.txt");
			f.write(display(set5A));
			f.close();
			f = new FileWriter("ListCCSLg6.txt");
			f.write(display(set6A));
			f.close();
			
			
			f = new FileWriter("NbCCM.txt");
			f.write(set1M.size() + " ");
			f.write(set2M.size() + " ");
			f.write(set3M.size() + " ");
			f.write(set4M.size() + " ");
			f.write(set5M.size() + " ");
			f.write(set6M.size() + "\n");
			f.close();
			
			f = new FileWriter("ListCCMLg1.txt");
			f.write(display(set1M));
			f.close();
			f = new FileWriter("ListCCMLg2.txt");
			f.write(display(set2M));
			f.close();
			f = new FileWriter("ListCCMLg3.txt");
			f.write(display(set3M));
			f.close();
			f = new FileWriter("ListCCMLg4.txt");
			f.write(display(set4M));
			f.close();
			f = new FileWriter("ListCCMLg5.txt");
			f.write(display(set5M));
			f.close();
			f = new FileWriter("ListCCMLg6.txt");
			f.write(display(set6M));
			f.close();
			
			f = new FileWriter("NbCCMS.txt");
			f.write(set1AM.size() + " ");
			f.write(set2AM.size() + " ");
			f.write(set3AM.size() + " ");
			f.write(set4AM.size() + " ");
			f.write(set5AM.size() + " ");
			f.write(set6AM.size() + "\n");
			f.close();
			
			f = new FileWriter("ListCCMSLg1.txt");
			f.write(display(set1AM));
			f.close();
			f = new FileWriter("ListCCMSLg2.txt");
			f.write(display(set2AM));
			f.close();
			f = new FileWriter("ListCCMSLg3.txt");
			f.write(display(set3AM));
			f.close();
			f = new FileWriter("ListCCMSLg4.txt");
			f.write(display(set4AM));
			f.close();
			f = new FileWriter("ListCCMSLg5.txt");
			f.write(display(set5AM));
			f.close();
			f = new FileWriter("ListCCMSLg6.txt");
			f.write(display(set6AM));
			f.close();
		}
		catch (IOException e)
		{
			System.out.println("Erreur lors de l'export des codes :");
			e.printStackTrace();
		}
	}

	String display(ArrayList<Code> s)
	{
		String str = "";
		
		for (Code c : s)
		{
			str += c.toString() + "\n";
		}
		
		// Ouput vide, on le termine par \n
		if (str == "")
		{
			str = "\n";
		}
		
		return str;
	}
	
}